package com.todod.common.util;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.BigDecimalConverter;
import org.apache.commons.beanutils.converters.DateConverter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public final class BeanUtilEx extends BeanUtils {

	private static Map cache = new HashMap();
	private static Log logger = LogFactory.getFactory().getInstance(BeanUtilEx.class);

	private BeanUtilEx() {
	}

	static {

		// ConvertUtils.register(new SqlDateConverter(null),
		// java.sql.Date.class);
		// 注册sql.date的转换器，即允许BeanUtils.copyProperties时的源目标的sql类型的值允许为空
		ConvertUtils.register(new SqlTimestampConverter(null), java.sql.Timestamp.class);

		ConvertUtils.register(new BigDecimalConverter(null), java.math.BigDecimal.class);
	}

	public static void copyProperties(Object target, Object source)
			throws InvocationTargetException, IllegalAccessException {

		// 支持对日期copy
		ConvertUtils.register(new DateConverter(null), java.util.Date.class);
		org.apache.commons.beanutils.BeanUtils.copyProperties(target, source);

	}

	/**
	 * @throws InvocationTargetException @throws IllegalArgumentException @throws
	 * IllegalAccessException @throws IntrospectionException
	 * 
	 * @Title: merge @Description: 合并bean(空字段合并) @author：gsh @param @param target
	 * 目的bean @param @param destination 合并bean @param @throws Exception @return
	 * void @throws
	 */
	public static <M> void merge(M target, M destination)
			throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		BeanInfo beanInfo = Introspector.getBeanInfo(target.getClass());

		// Iterate over all the attributes
		for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {

			// Only copy writable attributes
			if (descriptor.getWriteMethod() != null) {
				Object originalValue = descriptor.getReadMethod().invoke(target);

				// Only copy values values where the destination values is null
				if (originalValue == null) {
					Object defaultValue = descriptor.getReadMethod().invoke(destination);
					descriptor.getWriteMethod().invoke(target, defaultValue);
				}

			}
		}
	}

	/**
	 * @Title: mergeAll @Description: 合并bean(B中非空字段复制到A) @author：gsh @param target
	 * 目的bean @param destination 合并bean @throws Exception @return void @throws
	 */
	public static <M> void mergeAll(M target, M destination)
			throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		BeanInfo beanInfo = Introspector.getBeanInfo(destination.getClass());

		for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {

			if (descriptor.getWriteMethod() != null) {
				Object originalValue = descriptor.getReadMethod().invoke(destination);

				if (originalValue != null) {
					descriptor.getWriteMethod().invoke(target, originalValue);
				}

			}
		}
	}

	/**
	 * @Title: mergeAll
	 * @Description: 合并bean(B中非空字段复制到A)(指定属性不复制)
	 * @author：gsh
	 * @param target      目的bean
	 * @param destination 合并bean
	 * @throws Exception
	 * @return void
	 */
	public static <M> void mergeAll(M target, M destination, List<String> notMerg)
			throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		BeanInfo beanInfo = Introspector.getBeanInfo(destination.getClass());

		for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
			if (notMerg.contains(descriptor.getName())) // 指定属性不复制
				continue;
			if (descriptor.getWriteMethod() != null) {
				Object originalValue = descriptor.getReadMethod().invoke(destination);

				if (originalValue != null) {
					descriptor.getWriteMethod().invoke(target, originalValue);
				}

			}
		}
	}
}